# !/usr/bin/env python
# encoding: utf-8


"""
  @author: gaogao
  @file: mux_heater2_iv_test.py
  @time: 2022/5/11 9:35
  @desc:
"""

import time

from math import *
from ATS.application.LCR_App.U2722A_App import U2722A_App
from ATS.application.LASER_App.L8164B_App import L8164B_App
from ATS.application.LCR_App.B2901BL_App import B2901BLApp
from ATS.application.LASER_App.N7744C_App import N7744C_App
from ATS.datamanager import data_transfer_station as DataTransferStation
from ATS.application.VNA_App.N5225B_App import N5225BApp
from scipy.signal import savgol_filter
from ATS.util.calcu_step_util import get_points_list
from ATS.util.save_data_2_csv_util import saveData2CSV
from matplotlib import pyplot as plt
import numpy as np
from utils.find3db_util import find3db_util
from utils.find_first_minimum_util import find_first_minimaxmum
from utils.save_setting_2_ini import save_ini_info
from gui import constant
from collections import namedtuple
from utils.log_util import loggings
from gui.driver.var_manager import VarManager
from utils.auto_range import auto_range
from utils.save_data_2_file import save_spot_data_2_file
from database.entity.chip import Chip
from database.db_interface import insert_chip
try:
    from ATS.switchdriver.LightSwitchDriver import LightSwitchDriver
except Exception as e:
    raise ValueError("光开关不在线，请重启光开关！")


def mux_heater2_iv_test(para):
    try:
        result_data = namedtuple("result_data", "file_name,curve_type,y_invert,title,x_label,y_label,test_result")

        inst_light = LightSwitchDriver.instance()
        if not inst_light.is_connected:
            inst_light.connect()
        inst_light.set_all_switch("01", "05")
        time.sleep(1)
        loggings.info("switch" + str(inst_light.query_switch()))


        l8164b_app = L8164B_App(para.l8164_setting["title"])
        l8164b_app.set_power_unit()
        l8164b_app.set_power_value(para.l8164_setting["power_value"])
        wave_length = para.l8164_setting["wave_length"][0]
        l8164b_app.set_wave_length(wave_length)
        time.sleep(int(para.l8164_setting["stable_time"]))
        l8164b_app.output_on()

        smu_setting = para.smu_setting
        smu_dict = {}
        # smu voltage_list channel nplc current_range current_limit //mode sweep
        #
        mes_plans_dict = {"var_func": None, "var1": None, "measure_func": None}
        init_set_list = []
        set_range_dict = {"set_range_limit": None}
        sweep_channel_open = {"sweep": None}
        sweep_measure = {"sweep_func": None}
        if smu_setting:
            for smu in smu_setting:
                if smu["smu"] == "SMU10":
                    B2901BLApp(smu["smu"]).spot_setting(smu["voltage_list"][0], smu["current_limit"])
                else:
                    if smu["smu"] not in smu_dict:
                        smu_dict[smu["smu"]] = U2722A_App(smu["smu"])
                    current_inst = smu_dict[smu["smu"]]
                    current_voltage_list = smu["voltage_list"]
                    current_channel = smu["channel"]
                    current_channel_nplc = smu["nplc"]
                    current_channel_range = smu["current_range"]
                    current_channel_limit = smu["current_limit"]
                    init_set_list += [lambda y=current_channel,
                                             inst_obj=current_inst: inst_obj.output_state(0, y),

                                      lambda x=current_channel, inst_obj=current_inst: inst_obj.set_voltage_range(x),
                                      lambda x=current_channel_nplc, y=current_channel,
                                             inst_obj=current_inst: inst_obj.set_current_nplc(x, y),
                                      lambda x=current_channel_range, y=current_channel_limit,
                                             z=current_channel, inst_obj=current_inst: inst_obj.set_current_range_limit(x, y,
                                                                                                                        z)]
                    if smu["mode"] == "sweep":
                        mes_plans_dict["var1"] = current_voltage_list
                        mes_plans_dict["var_func"] = lambda volt, x=current_channel, inst_obj=current_inst: \
                            inst_obj.set_voltage(volt, x)
                        sweep_channel_open["sweep"] = lambda y=current_channel, inst_obj=current_inst: inst_obj.output_state(1,
                                                                                                                             y)

                        sweep_measure["sweep_func"] = lambda x=current_channel, inst_obj=current_inst: abs(
                            float(inst_obj.get_current_value(x)))
                    else:
                        init_set_list += [lambda volt=current_voltage_list[0], x=current_channel, inst_obj=current_inst: \
                                              inst_obj.set_voltage(volt, x)]

                    if smu["is_measure"]:
                        set_range_dict["set_range_limit"] = lambda range, limit, z=current_channel,inst_obj=current_inst: inst_obj.set_current_range_limit(
                            range, limit, z)
                        actual_range = smu["current_range"]
                        mes_plans_dict["measure_func"] = lambda x=current_channel, inst_obj=current_inst: abs(
                            float(inst_obj.get_current_value(x)))
                    init_set_list += [lambda y=current_channel, inst_obj=current_inst: inst_obj.output_state(1, y)]

            # set init
            for inst_set_func in init_set_list:
                inst_set_func()  # 设置SMU

            # read mes
            current_list = []  # result list
            mes_func = mes_plans_dict["measure_func"]
            if mes_func:  # mes func不为空
                if mes_plans_dict["var1"]:  # sweep
                    for volt in mes_plans_dict["var1"]:
                        mes_plans_dict["var_func"](volt)
                        me_current = mes_func()
                        current_list.append(me_current)
                        is_variety, current_range, limit = auto_range(me_current, actual_range)
                        if is_variety:
                            actual_range = current_range
                            set_range_dict["set_range_limit"](actual_range, limit)
                            mes_plans_dict["var_func"](volt)
                            me_current = mes_func()
                            current_list[-1] = me_current
                else:
                    current_list.append(mes_func())  # spot

            voltage_list = [float(i) for i in mes_plans_dict["var1"]]
            title_section = f"{VarManager().diex}-{VarManager().diey}&{VarManager().subdie_name}&{para.subdie}&{wave_length}_{para.test_item}"
            title_path = f"{VarManager().save_folder}/{VarManager().wafer_name}"
            if all([voltage_list, current_list]):
                curve_title = f"{title_section}"
                x_label = "Voltage"
                y_label = "Current"

                DataTransferStation.get_DTS().postarraydata("test",
                                                            result_data(f"{title_section}", "line", False,curve_title,x_label,y_label,
                                                                        (voltage_list, current_list)))

                chip_name = f"{VarManager().subdie_name}"
                wafer_name = VarManager().wafer_name
                shot_position = f"{VarManager().diex},{VarManager().diey}"
                shot_number = VarManager().shot_number
                chip_number = VarManager().subdie_number
                polarization_type = VarManager().polarization_type
                measurement_parameter = f"{para.subdie}_{para.test_item}_{wave_length}_IV"
                measurement_data = str([voltage_list, current_list])
                data_unit = ""
                data_type = "Curve"
                insert_chip(chip_name, wafer_name, shot_position, shot_number, chip_number, polarization_type,
                     measurement_parameter, measurement_data, data_unit, data_type)

                VL, VH = find_first_minimaxmum(voltage_list, current_list)
                if VL is not None and VH is not None:
                    mes_plans_dict["var_func"](VL)
                    sweep_current = sweep_measure["sweep_func"]()
                    close_all_channel()

                    sweep_channel_open["sweep"]()
                    time.sleep(1)
                    save_spot_data_2_file(f"{title_path}.csv", f"{title_section}_VL2", str(VL))
                    save_spot_data_2_file(f"{title_path}.csv", f"{title_section}_VH2", str(VH))

                    mes_plans_dict["var_func"](VL)
                    heater_R = str(float(VL) / float(sweep_current))

                    save_spot_data_2_file(f"{title_path}.csv", f"{title_section}&Heater_R2", heater_R)

                    measurement_parameter = f"{para.subdie}_{para.test_item}_{wave_length}_VL2"
                    measurement_data = str(VL)
                    data_unit = "V"
                    data_type = "Spot"
                    insert_chip(chip_name, wafer_name, shot_position, shot_number, chip_number, polarization_type,
                         measurement_parameter, measurement_data, data_unit, data_type)

                    measurement_parameter = f"{para.subdie}_{para.test_item}_{wave_length}_VH2"
                    measurement_data = str(VH)
                    data_unit = "V"
                    data_type = "Spot"
                    insert_chip(chip_name, wafer_name, shot_position, shot_number, chip_number, polarization_type,
                         measurement_parameter, measurement_data, data_unit, data_type)

                    measurement_parameter = f"{para.subdie}_{para.test_item}_{wave_length}&Heater_R2"
                    measurement_data = heater_R
                    data_unit = "ohm"
                    data_type = "Spot"
                    insert_chip(chip_name, wafer_name, shot_position, shot_number, chip_number, polarization_type,
                         measurement_parameter, measurement_data, data_unit, data_type)
    except Exception as e:
        loggings.error("mux_heater2_iv_test" + str(e))


def close_all_channel():
    U2722A_App("SMU2").close_all_channel()
    U2722A_App("SMU3").close_all_channel()
    U2722A_App("SMU4").close_all_channel()
    B2901BLApp("SMU10").output_close()


mux_heater2_iv_test(locals()["para"])
